// 题目描述
// 讨论 (254)
// LCR 016. 无重复字符的最长子串
// 中等
// 91
// 给定一个字符串 s ，请你找出其中不含有重复字符的 最长连续子字符串 的长度。
//   示例 1:
// 输入: s = "abcabcbb"
// 输出: 3
// 解释: 因为无重复字符的最长子字符串是 "abc"，所以其长度为 3。
// 示例 2:
// 输入: s = "bbbbb"
// 输出: 1
// 解释: 因为无重复字符的最长子字符串是 "b"，所以其长度为 1。
// 示例 3:
// 输入: s = "pwwkew"
// 输出: 3
// 解释: 因为无重复字符的最长子串是 "wke"，所以其长度为 3。
//      请注意，你的答案必须是 子串 的长度，"pwke" 是一个子序列，不是子串。
// 示例 4:
// 输入: s = ""
// 输出: 0
//   提示：
// 0 <= s.length <= 5 * 104
// s 由英文字母、数字、符号和空格组成
//   注意：本题与主站 3 题相同： https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
// 通过次数
// 50.3K
// 提交次数
// 105.7K
// 通过率
// 47.5%
// https://leetcode.cn/problems/wtcaE1

/**
 * @param {string} s
 * @return {number}
 */
/**
 * @param {string} s
 * @return {number}
 */
const lengthOfLongestSubstring = function (s) {
  // base case
  if (s.length < 2) {
    return s.length
  }

  // 记录每个字符最后一次出现的位置
  const hash = {}

  // 返回结果为滑动窗口的最大宽度
  let res = 0

  // 记住边界 i = 0, j = -1
  // i <= len - 1, j = Math.max(j, hash[s[i]])
  for (let i = 0, j = -1, len = s.length; i < len; i++) {
    const cur = s[i]

    // 如果 hash 中缓存过 cur，说明窗口中出现了重复字符
    // 需要收缩
    if (hash[cur] !== undefined) {
      // 具体收缩的地方就是 j 最后一次出现的位置的下一位
      // 这里为了方便计算 j 始终是左边界下标 - 1
      j = Math.max(j, hash[cur])
    }

    // 将当前遍历过的字符装入 hash 表
    hash[cur] = i

    // 更新滑动窗口的最大宽度
    res = Math.max(res, i - j)
  }

  return res
}

console.log(lengthOfLongestSubstring('abcabcbb')) // 3
